﻿using ASmile.DBModel;
using ASmile.Helpers;
using ASmile.ORM.Entitys;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using ASmile.Extend;
using ASmile.ORM.Cores;
using System.Threading;

namespace ASmile.Com
{
    public enum EmDataCacheCom
    {
        WordCode,
        CfgDict,
        GridColumn,
        RoleUrl,
        Report,
        ReportArg
    }

    /// <summary>
    /// 缓存工具类，以后改造从Redis获取
    /// </summary>
    public class DataCacheTool
    {
        public static T GetCacheData<T>(string key) where T : class
        {
            return MemoryCacheHelper.Get<T>(key);
        }

        public static List<T> GetCacheListData<T>(string key) where T : class
        {
            return GetCacheData<List<T>>(key);
        }

        public static bool SetCacheData(string key, object data, int? expiresSec = null)
        {
            if (expiresSec == null)
            {
                return MemoryCacheHelper.Set(key, data);
            }
            else
            {
                return MemoryCacheHelper.Set(key, data, expiresSec.Value);
            }
        }
    }

    public class DataCacheCom
    {
        static DBContext BLLObj { get; set; }

        /// <summary>
        /// 系统启动时异步加载缓存,返回 Task
        /// </summary>
        public static Task Init(DBContext da)
        {
            BLLObj = da;
            
            var task =
            Task.Factory.StartNew(() =>
            {
                if (!ConfigCom.M.EnableCache)
                {
                    LogHelper.LogObj.Info("未启用缓存");
                    return;
                }
                LogHelper.LogObj.Info("开始系统数据缓存");
                LoadGridColumn();
                LoadWordCodeCache();
                LoadCfgDict();
                LoadRoleUrlCache();
                LoadReport();
                LoadReportArg();
            });
            return task;
        }

        public static System.Collections.IList SyncDataCache(EmDataCacheCom cacheType)
        {
            switch (cacheType)
            {
                case EmDataCacheCom.WordCode: return LoadWordCodeCache();
                case EmDataCacheCom.CfgDict: return LoadCfgDict();
                case EmDataCacheCom.GridColumn: return LoadGridColumn();
                case EmDataCacheCom.RoleUrl: return LoadRoleUrlCache();
                case EmDataCacheCom.Report: return LoadReport();
                case EmDataCacheCom.ReportArg: return LoadReportArg();
                default: return null;
            }
        }

        /// <summary>
        /// 赋值一个数据库对象的属性值到另一个对象（深拷贝）
        /// </summary>
        public static void CopyDbModel<TEntity>(TEntity targetObj, TEntity sourceObj)
            where TEntity : EntityBase, new()
        {
            Type tarType = targetObj.GetType();
            PropertyInfo[] tarProInfos = tarType.GetProperties();

            foreach (var tarPro in tarProInfos)
            {
                //PropertyInfo objProInfo = ReflectionHelper.GetPropertyInfo(sourceObj, tarPro.Name);
                if (!tarPro.CanWrite) continue;
                if (!sourceObj.IsChangeField(tarPro.Name)) continue;

                object srcProVal = tarPro.GetValue(sourceObj, null);

                tarPro.SetValue(targetObj, srcProVal, null);
            }
        }

        static List<T> GetCacheListData<T>(string key) where T : class
        {
            return DataCacheTool.GetCacheListData<T>(key);
        }

        static bool SetCacheData(string key, object data, int? expiresSec = null)
        {
            return DataCacheTool.SetCacheData(key, data, expiresSec);
        }

        #region 助记码

        const string CK_WordCode = "{54F52F3E-E075-44DA-969F-CCF9CC0ABC9C}";

        public static List<Dict_WordCode> LoadWordCodeCache()
        {
            var rList = BLLObj.Query<Dict_WordCode>(s => s.IsEnable == true).ToList();
            if (rList != null)
            {
                SetCacheData(CK_WordCode, rList);
                LogHelper.LogObj.Info($"加载[助记码]缓存完成, 记录数:{rList.Count}");
            }
            return rList;
        }

        public static List<Dict_WordCode> GetWordCode()
        {
            var rList = GetCacheListData<Dict_WordCode>(CK_WordCode);
            return rList;
        }

        static Dict_WordCode GetWordCode(string word)
        {
            var rList = GetWordCode();
            return rList.Find(s => s.WordName == word);
        }

        public static bool GetWordCode(string src, out string pyCode, out string wbCode)
        {
            var rList = GetWordCode();
            if (rList == null)
            {
                pyCode = string.Empty;
                wbCode = string.Empty;
                return false;
            }
            List<string> pyList = new List<string>();
            List<string> wbList = new List<string>();
            foreach (var item in src)
            {
                var word = rList.Find(s => s.WordName == item.ToString());
                if (word != null)
                {
                    pyList.Add(word.WordPY);
                    wbList.Add(word.WordWB);
                }
            }
            pyCode = string.Join("", pyList);
            wbCode = string.Join("", wbList);
            return true;
        }

        public static string GetWordCodePY(string src)
        {
            GetWordCode(src, out string pyCode, out _);
            return pyCode;
        }

        public static string GetWordCodeWB(string src)
        {
            GetWordCode(src, out string _, out string wbCode);
            return wbCode;
        }

        public static void WordCodeAdd(Dict_WordCode model)
        {
            var rList = GetWordCode();
            rList.Add(model);
        }

        public static void WordCodeEdit(Dict_WordCode model)
        {
            var srcModel = GetWordCode(model.WordName);
            if (srcModel == null)
            {
                WordCodeAdd(model);
                return;
            }
            CopyDbModel(srcModel, model);
        }

        public static void WordCodeDel(string wordName)
        {
            List<Dict_WordCode> rList = GetWordCode();
            rList.Remove(s => s.WordName == wordName);
        }

        #endregion

        #region 配置字典

        const string CK_CfgDict = "{7723A3D9-737A-44BD-94AA-30466222098A}";

        public static List<Cfg_Dict> LoadCfgDict()
        {
            var rList = BLLObj.Query<Cfg_Dict>(s => true).ToList();
            if (rList != null)
            {
                SetCacheData(CK_CfgDict, rList);
                LogHelper.LogObj.Info($"加载[配置字典]缓存完成, 记录数:{rList.Count}");
            }
            return rList;
        }

        public static void CfgDictEdit(Cfg_Dict model)
        {
            var srcModel = GetCfgDict(model.CfgId);
            if (srcModel == null)
            {
                return;
            }
            CopyDbModel(srcModel, model);
        }

        public static Cfg_Dict GetCfgDict(string cfgId)
        {
            var rList = GetCacheListData<Cfg_Dict>(CK_CfgDict);
            if (rList == null) return null;

            return rList.Find(s => s.CfgId == cfgId);
        }

        /// <summary>
        /// 获取配置字符串值
        /// </summary>
        public static string GetCfgValue(string key)
        {
            var cfg = GetCfgDict(key);
            return cfg?.CfgValue;
        }
        /// <summary>
        /// 获取配置Value
        /// </summary>
        public static T GetCfgValue<T>(string key)
        {
            var cfg = GetCfgDict(key);
            if (cfg == null) return default(T);
            var val = Convert.ChangeType(cfg.CfgValue, typeof(T));
            return (T)val;
        }

        #endregion

        #region GridView 列信息

        const string CK_GridColumn = "{9E851319-3C4A-4197-837F-0ABE7800CDC6}";

        public static List<Sys_GridColumn> LoadGridColumn()
        {
            var rList = BLLObj.Query<Sys_GridColumn>(s => true).ToList();
            if (rList != null)
            {
                SetCacheData(CK_GridColumn, rList);
                LogHelper.LogObj.Info($"加载[Grid列信息]缓存完成, 记录数:{rList.Count}");
            }
            return rList;
        }

        public static List<Sys_GridColumn> GetGridColumn()
        {
            var rList = GetCacheListData<Sys_GridColumn>(CK_GridColumn);
            if (rList == null) return null;
            return rList;
        }

        public static List<Sys_GridColumn> GetGridColumn(Predicate<Sys_GridColumn> match)
        {
            var rList = GetGridColumn();
            if (rList == null) return null;
            return rList.FindAll(match);
        }

        public static Sys_GridColumn GetGridColumn(string id)
        {
            var r = GetGridColumn(s => s.Id == id);
            return r?.FirstOrDefault();
        }

        public static void GridColumnAdd(Sys_GridColumn model)
        {
            var rList = GetGridColumn();
            rList.Add(model);
        }

        public static void GridColumnEdit(Sys_GridColumn model)
        {
            var srcModel = GetGridColumn(model.Id);
            if (srcModel == null)
            {
                return;
            }
            CopyDbModel(srcModel, model);
        }

        public static void GridColumnDel(string id)
        {
            List<Sys_GridColumn> rList = GetGridColumn();
            rList?.Remove(s => s.Id == id);
        }

        #endregion

        #region RoleUrl

        const string CK_RoleUrl = "{212AEFAD-58C7-4526-8E2A-52FEB89ADD88}";

        public static List<Sys_RoleUrl> LoadRoleUrlCache()
        {
            var rList = BLLObj.Query<Sys_RoleUrl>(s => true).ToList();
            if (rList != null)
            {
                SetCacheData(CK_RoleUrl, rList);
                LogHelper.LogObj.Info($"加载[角色URL]缓存完成, 记录数:{rList.Count}");
            }
            return rList;
        }

        public static List<Sys_RoleUrl> GetRoleUrl()
        {
            var rList = GetCacheListData<Sys_RoleUrl>(CK_RoleUrl);
            //if (rList == null)
            //{
            //    rList = LoadRoleUrlCache();
            //}
            return rList;
        }

        public static List<Sys_RoleUrl> GetRoleUrl(Predicate<Sys_RoleUrl> match)
        {
            var rList = GetCacheListData<Sys_RoleUrl>(CK_RoleUrl);
            return rList?.FindAll(match);
        }

        public static List<Sys_RoleUrl> GetRoleUrlByRoleId(string roleId)
        {
            return GetRoleUrl(s => s.RoleId == roleId);
        }

        public static Sys_RoleUrl GetRoleUrl(string id)
        {
            return GetRoleUrl(s => s.Id == id)?.FirstOrDefault();
        }

        public static void RoleUrlAdd(Sys_RoleUrl model)
        {
            var rList = GetRoleUrl();
            if (rList == null)
            {
                rList = new List<Sys_RoleUrl>();
            }
            rList.Add(model);
        }

        public static void RoleUrlEdit(Sys_RoleUrl model)
        {
            var srcModel = GetRoleUrl(model.Id);
            if (srcModel == null)
            {
                RoleUrlAdd(model);
            }
            else
            {
                CopyDbModel(srcModel, model);
            }
        }

        public static void RoleUrlDel(string id)
        {
            List<Sys_RoleUrl> rList = GetRoleUrl();
            rList.Remove(s => s.Id == id);
        }

        #endregion

        #region 报表查询 & 报表参数 的配置

        const string CK_Report = "{DFE4BC9C-C5FD-4BC6-BAFC-08A9D4E79D04}";

        public static List<Sys_Report> LoadReport()
        {
            var rList = BLLObj.Query<Sys_Report>(s => true).ToList();
            if (rList != null)
            {
                SetCacheData(CK_Report, rList);
                LogHelper.LogObj.Info($"加载[Report]缓存完成, 记录数:{rList.Count}");
            }
            return rList;
        }

        public static List<Sys_Report> GetReport()
        {
            var rList = GetCacheListData<Sys_Report>(CK_Report);
            if (rList == null) return null;
            return rList;
        }

        public static List<Sys_Report> GetReport(Predicate<Sys_Report> match)
        {
            var rList = GetReport();
            if (rList == null) return null;
            return rList.FindAll(match);
        }

        public static Sys_Report GetReportById(string id)
        {
            var r = GetReport(s => s.Id == id);
            return r?.FirstOrDefault();
        }

        public static Sys_Report GetReport(string formName)
        {
            var r = GetReport(s => s.FormName == formName);
            return r?.FirstOrDefault();
        }

        public static void ReportAdd(Sys_Report model)
        {
            var rList = GetReport();
            if (rList == null)
            {
                rList = new List<Sys_Report>();
            }
            rList.Add(model);
        }

        public static void ReportEdit(Sys_Report model)
        {
            var srcModel = GetReportById(model.Id);
            if (srcModel == null)
            {
                return;
            }
            CopyDbModel(srcModel, model);
        }

        public static void ReportDel(string id)
        {
            List<Sys_Report> rList = GetReport();
            rList?.Remove(s => s.Id == id);
        }

        const string CK_ReportArg = "{96A76F0B-E712-43A7-AE04-4F09D0B30F99}";

        public static List<Sys_ReportArg> LoadReportArg()
        {
            var rList = BLLObj.Query<Sys_ReportArg>(s => true).ToList();
            if (rList != null)
            {
                SetCacheData(CK_ReportArg, rList);
                LogHelper.LogObj.Info($"加载[Report arg]缓存完成, 记录数:{rList.Count}");
            }
            return rList;
        }

        public static List<Sys_ReportArg> GetReportArg()
        {
            var rList = GetCacheListData<Sys_ReportArg>(CK_ReportArg);
            if (rList == null) return null;
            return rList;
        }

        public static List<Sys_ReportArg> GetReportArg(Predicate<Sys_ReportArg> match)
        {
            var rList = GetReportArg();
            if (rList == null) return null;
            return rList.FindAll(match);
        }

        public static Sys_ReportArg GetReportArgById(string id)
        {
            var r = GetReportArg(s => s.Id == id);
            return r?.FirstOrDefault();
        }

        public static void ReportArgAdd(Sys_ReportArg model)
        {
            var rList = GetReportArg();
            if (rList == null)
            {
                rList = new List<Sys_ReportArg>();
            }
            rList.Add(model);
        }

        public static void ReportArgEdit(Sys_ReportArg model)
        {
            var srcModel = GetReportArgById(model.Id);
            if (srcModel == null)
            {
                return;
            }
            CopyDbModel(srcModel, model);
        }

        public static void ReportArgDel(string id)
        {
            List<Sys_ReportArg> rList = GetReportArg();
            rList?.Remove(s => s.Id == id);
        }

        #endregion
    }
}